﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using QuantitativeInvestment.Bean;
using QuantitativeInvestment.Model;
using QuantitativeInvestment.Factor;
using QuantitativeInvestment.CharacterAnalyzer;
namespace QuantitativeInvestment.Tools
{
    class XmlDataSource
    {
        public XmlDocument doc;

        public XmlElement currentElement;
        public XmlDataSource()
        {
            this.doc = new XmlDocument();
            XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", "GB2312", null);
            doc.AppendChild(dec); 
        }
     
        
        public void ouputContainer(Container.Container container,string fileName)
        {
            XmlElement root = doc.CreateElement("Container");
            doc.AppendChild(root);

            XmlElement e = doc.CreateElement("Name");
            e.InnerText = container.name;
            root.AppendChild(e);

            this.addParameters(container.paraList, root);
            XmlElement eModels = doc.CreateElement("Models");
            root.AppendChild(eModels);
            foreach (Model.Model model in container.modelList)
            {
                XmlElement eModel = doc.CreateElement("Model");
                eModels.AppendChild(eModel);

                e = doc.CreateElement("Name");
                e.InnerText = model.name;
                eModel.AppendChild(e);

                this.addParameters(model.paraList, eModel);

                XmlElement eFactors = doc.CreateElement("Factors");
                eModel.AppendChild(eFactors);

                foreach (Factor.Factor factor in model.factorList)
                {
                    XmlElement eFactor = doc.CreateElement("Model");
                    eFactors.AppendChild(eFactor);

                    e = doc.CreateElement("Name");
                    e.InnerText = factor.name;
                    eFactor.AppendChild(e);
                    this.addParameters(factor.paraList, eFactor);

                }

            }

            XmlElement eAnalyzers = doc.CreateElement("Analyzers");
            root.AppendChild(eAnalyzers);
            foreach (CharacterAnalyzer.CharacterAnalyzer analyzer in container.analyserList)
            {
                XmlElement eAnalyzer = doc.CreateElement("Analyzer");
                eAnalyzers.AppendChild(eAnalyzer);

                e = doc.CreateElement("Name");
                e.InnerText = analyzer.name;
                eAnalyzer.AppendChild(e);    
            }


            doc.Save(fileName); 
   
        }
        private void addParameters(Dictionary<string,Parameter> paraList,XmlElement ePosition)
        {
            XmlElement eParameters = doc.CreateElement("Parameters");
            ePosition.AppendChild(eParameters);
            foreach (Parameter p in paraList.Values)
            {
                XmlElement eParameter = doc.CreateElement("Parameter");
                eParameters.AppendChild(eParameter);
                XmlElement e = doc.CreateElement("Name");
                e.InnerText = p.name;
                eParameter.AppendChild(e);

                e = doc.CreateElement("Value");
                e.InnerText = p.value.ToString();
                eParameter.AppendChild(e);

                e = doc.CreateElement("Type");
                e.InnerText = p.type;
                eParameter.AppendChild(e);

                if (p.type == "enum")
                {

                    XmlElement enumList = doc.CreateElement("EnumList");
                    eParameter.AppendChild(enumList);

                    foreach (string value in p.enumList)
                    {
                        e = doc.CreateElement("Enum");
                        e.InnerText = value;
                        enumList.AppendChild(e);
                    }
                }
            }
        }
        public Container.Container readContainer(string fileName)
        {
            this.doc.Load(fileName);
            XmlNode root = doc.SelectSingleNode("Container");
            XmlNode containerNameNode = root.SelectSingleNode("Name");
            string containerName = containerNameNode.InnerText;
            Container.Container container = Container.Container.createContainerByName(containerName);

             XmlNode parametersNode = root.SelectSingleNode("Parameters");
             Dictionary<string, Parameter> paraList=this.readParameters(parametersNode);
             foreach (Parameter p in paraList.Values)
             {
                 container.paraList[p.name].value = p.value;
             }

            XmlNode nodeModels = root.SelectSingleNode("Models");
            XmlNodeList modelNodeList = nodeModels.SelectNodes("Model");
            foreach (XmlElement eModel in modelNodeList)
            {
                XmlNode nodeModelName=eModel.SelectSingleNode("Name");
                Model.Model model = Model.Model.createModelByName(nodeModelName.InnerText);

                model.container = container;
                container.modelList.Add(model);

                parametersNode = eModel.SelectSingleNode("Parameters");
                paraList = this.readParameters(parametersNode);
                foreach (Parameter p in paraList.Values)
                {
                    model.paraList[p.name].value = p.value;
                }
                XmlNodeList nodeFactorList = eModel.SelectSingleNode("Factors").SelectNodes("Factor");
                
                foreach(XmlNode nodeFactor in nodeFactorList)
                {
                    string factorName = nodeFactor.SelectSingleNode("Name").InnerText;
                    Factor.Factor factor = Factor.Factor.createFactorByName(factorName);

                    parametersNode = nodeFactor.SelectSingleNode("Parameters");
                    paraList = this.readParameters(parametersNode);
                    foreach (Parameter p in paraList.Values)
                    {
                        factor.paraList[p.name].value = p.value;
                    }
                    model.factorList.Add(factor);
                }


            }

            return container;
        }
        private Dictionary<string,Parameter> readParameters( XmlNode parameters)
        {
            Dictionary<string, Parameter> paraList = new Dictionary<string, Parameter>();
            XmlNodeList nodeList= parameters.ChildNodes;
            foreach (XmlElement element in parameters.ChildNodes)
            {
                XmlNodeList nameNodeList= element.GetElementsByTagName("Name");
                string name = nameNodeList[0].InnerText;
                XmlNodeList valueNodeList = element.GetElementsByTagName("Value");
                object value = valueNodeList[0].InnerText;
                Parameter p = new Parameter(name, value);
                paraList.Add(p.name,p);
            }
            return paraList;
        }
        public void outputPortfolios( List<Portfolio> portfolioList,string fileName,bool isDetailed=true)
        {

            XmlElement root = doc.CreateElement("Portfolios");
            doc.AppendChild(root);
   
            double accumulatedEarning = 0;
            double accumulatedExcessEarning = 0;

            for (int i = 0; i < portfolioList.Count; i++)
            {
                XmlElement portfolioElement = doc.CreateElement("Portfolio");
                root.AppendChild(portfolioElement);

                XmlElement startDateElement = doc.CreateElement("StartDate");
                startDateElement.InnerText = portfolioList[i].startDate;
                portfolioElement.AppendChild(startDateElement);

                XmlElement endDateElement = doc.CreateElement("EndDate");
                endDateElement.InnerText = portfolioList[i].endDate;
                portfolioElement.AppendChild(endDateElement);

                XmlElement accumulateIncreasePortfolioElement = doc.CreateElement("AccumulateIncrease");
                accumulatedEarning = (1 + portfolioList[i].averageIncrease) * (1 + accumulatedEarning) - 1;
                accumulateIncreasePortfolioElement.InnerText = accumulatedEarning.ToString();
                portfolioElement.AppendChild(accumulateIncreasePortfolioElement);

                XmlElement avgIncreaseElement = doc.CreateElement("AvgIncrease");
                avgIncreaseElement.InnerText = portfolioList[i].averageIncrease.ToString();
                portfolioElement.AppendChild(avgIncreaseElement);

                XmlElement minIncrease = doc.CreateElement("MinIncrease");
                minIncrease.InnerText = portfolioList[i].minIncrease.ToString();
                portfolioElement.AppendChild(minIncrease);

                XmlElement maxIncrease = doc.CreateElement("MaxIncrease");
                maxIncrease.InnerText = portfolioList[i].maxIncrease.ToString();
                portfolioElement.AppendChild(maxIncrease);

                XmlElement benchMarkIncreaseElement = doc.CreateElement("BenchMarkIncrease");
                benchMarkIncreaseElement.InnerText = portfolioList[i].benchMarkIncrease.ToString();
                portfolioElement.AppendChild(benchMarkIncreaseElement);

                XmlElement excessIncreaseElement = doc.CreateElement("ExcessIncrease");
                excessIncreaseElement.InnerText = portfolioList[i].excessIncrease.ToString();
                portfolioElement.AppendChild(excessIncreaseElement);

                accumulatedExcessEarning = (1 + portfolioList[i].excessIncrease) * (1 + accumulatedExcessEarning) - 1;
                XmlElement accumulatedExcessEarningElement = doc.CreateElement("AccumulatedExcessEarning");
                accumulatedExcessEarningElement.InnerText = accumulatedExcessEarning.ToString();
                portfolioElement.AppendChild(accumulatedExcessEarningElement);

                foreach(Parameter parameter in portfolioList[i].characterList)
                {
                        XmlElement e = doc.CreateElement(parameter.name);
                        e.InnerText = parameter.value.ToString();
                        portfolioElement.AppendChild(e);
                }




                if (isDetailed)
                {
                    XmlElement stocksElement = doc.CreateElement("Stocks");
                    portfolioElement.AppendChild(stocksElement);
                    foreach (TradingStock tradingStock in portfolioList[i].stockList)
                    {
                        XmlElement stockElement = doc.CreateElement("Stock");
                        stocksElement.AppendChild(stockElement);

                        XmlElement e = doc.CreateElement("Code");
                        e.InnerText = tradingStock.code;
                        stockElement.AppendChild(e);

                        e = doc.CreateElement("Name");
                        e.InnerText = tradingStock.name;
                        stockElement.AppendChild(e);

                        e = doc.CreateElement("BuyDate");
                        e.InnerText = tradingStock.buyDate;
                        stockElement.AppendChild(e);

                        e = doc.CreateElement("BuyPrice");
                        e.InnerText = tradingStock.buyPrice.ToString();
                        stockElement.AppendChild(e);

                        e = doc.CreateElement("SellDate");
                        e.InnerText = tradingStock.sellDate;
                        stockElement.AppendChild(e);

                        e = doc.CreateElement("SellPrice");
                        e.InnerText = tradingStock.sellPrice.ToString();
                        stockElement.AppendChild(e);

                        e = doc.CreateElement("Increase");
                        e.InnerText = tradingStock.increase.ToString();
                        stockElement.AppendChild(e);
                    }
                }
            }
        }

        public void createTestModeDocument()
        {
            XmlElement root = doc.CreateElement("操作列表");
            this.doc.AppendChild(root);
            this.currentElement=root;
        }
       
        public void addPortfolios(Container.SimpleContainer simpleContainer,bool isDetailed=true)
        {


            XmlElement actionE = doc.CreateElement("容器");
            this.currentElement.AppendChild(actionE);


            foreach (Parameter p in simpleContainer.paraList.Values)
            {
                XmlElement actionParaE = doc.CreateElement(p.name);
                actionParaE.InnerText = p.value.ToString();
                actionE.AppendChild(actionParaE);
            }


            XmlElement modelES = doc.CreateElement("模型列表");
            actionE.AppendChild(modelES);
            foreach(Model.Model m in simpleContainer.modelList)
            {
                XmlElement modelE = doc.CreateElement(m.name);
                modelES.AppendChild(modelE);

                foreach(Parameter p in m.paraList.Values)
                {
                    XmlElement modelParaE = doc.CreateElement(p.name);
                    modelParaE.InnerText = p.value.ToString();
                    modelE.AppendChild(modelParaE);
                }
            }


            XmlElement accumulateIncreaseElement = doc.CreateElement("累计收益");
            accumulateIncreaseElement.InnerText = simpleContainer.portfolioMananger.accumulatedReturn.ToString();
            actionE.AppendChild(accumulateIncreaseElement);


            XmlElement accumulatedExcessEarningElement1 = doc.CreateElement("累计超额收益");
            accumulatedExcessEarningElement1.InnerText = simpleContainer.portfolioMananger.accumulatedExcessReturn.ToString();
            actionE.AppendChild(accumulatedExcessEarningElement1);


            XmlElement avgReturnE = doc.CreateElement("平均收益");
            avgReturnE.InnerText = simpleContainer.portfolioMananger.avgReturn.ToString();
            actionE.AppendChild(avgReturnE);

            XmlElement avgYearReturnE = doc.CreateElement("年化平均收益");
            avgYearReturnE.InnerText = simpleContainer.portfolioMananger.avgYearReturn.ToString();
            actionE.AppendChild(avgYearReturnE);

            XmlElement avgExcessReturnE = doc.CreateElement("平均超额");
            avgExcessReturnE.InnerText = simpleContainer.portfolioMananger.avgExcessReturn.ToString();
            actionE.AppendChild(avgExcessReturnE);

            XmlElement avgYearExcessReturnE = doc.CreateElement("年化平均超额");
            avgYearExcessReturnE.InnerText = simpleContainer.portfolioMananger.avgYearExcessReturn.ToString();
            actionE.AppendChild(avgYearExcessReturnE);

            XmlElement sucessRateE = doc.CreateElement("胜率");
            sucessRateE.InnerText = simpleContainer.portfolioMananger.successRate.ToString();
            actionE.AppendChild(sucessRateE);

            XmlElement excessReturnVariance = doc.CreateElement("超额方差");
            excessReturnVariance.InnerText = simpleContainer.portfolioMananger.excessIncreaseVariance.ToString();
            actionE.AppendChild(excessReturnVariance);


            XmlElement root = doc.CreateElement("组合列表");
            actionE.AppendChild(root);

            double accumulatedEarning = 0;
            double accumulatedExcessEarning = 0;

            List<Portfolio> portfolioList = simpleContainer.portfolioMananger.soldPortfolioList;

            for (int i = 0; i < portfolioList.Count; i++)
            {
                XmlElement portfolioElement = doc.CreateElement("组合");
                root.AppendChild(portfolioElement);

                XmlElement startDateElement = doc.CreateElement("开始时间");
                startDateElement.InnerText = portfolioList[i].startDate;
                portfolioElement.AppendChild(startDateElement);

                XmlElement endDateElement = doc.CreateElement("结束时间");
                endDateElement.InnerText = portfolioList[i].endDate;
                portfolioElement.AppendChild(endDateElement);

                XmlElement accumulateIncreasePortfolioElement = doc.CreateElement("累计收益");
                accumulatedEarning = (1 + portfolioList[i].averageIncrease) * (1 + accumulatedEarning) - 1;
                accumulateIncreasePortfolioElement.InnerText = accumulatedEarning.ToString();
                portfolioElement.AppendChild(accumulateIncreasePortfolioElement);

                XmlElement avgIncreaseElement = doc.CreateElement("平均收益");
                avgIncreaseElement.InnerText = portfolioList[i].averageIncrease.ToString();
                portfolioElement.AppendChild(avgIncreaseElement);


                XmlElement avgYearIncreaseElement = doc.CreateElement("年化收益");
                avgYearIncreaseElement.InnerText = portfolioList[i].averageYearIncrease.ToString();
                portfolioElement.AppendChild(avgYearIncreaseElement);


                XmlElement minIncrease = doc.CreateElement("最低");
                minIncrease.InnerText = portfolioList[i].minIncrease.ToString();
                portfolioElement.AppendChild(minIncrease);

                XmlElement maxIncrease = doc.CreateElement("最高");
                maxIncrease.InnerText = portfolioList[i].maxIncrease.ToString();
                portfolioElement.AppendChild(maxIncrease);

                XmlElement benchMarkIncreaseElement = doc.CreateElement("基准");
                benchMarkIncreaseElement.InnerText = portfolioList[i].benchMarkIncrease.ToString();
                portfolioElement.AppendChild(benchMarkIncreaseElement);

                XmlElement excessIncreaseElement = doc.CreateElement("超额");
                excessIncreaseElement.InnerText = portfolioList[i].excessIncrease.ToString();
                portfolioElement.AppendChild(excessIncreaseElement);

                XmlElement sucessRateElement = doc.CreateElement("胜率");
                sucessRateElement.InnerText = portfolioList[i].successRate.ToString();
                portfolioElement.AppendChild(sucessRateElement);

                accumulatedExcessEarning = (1 + portfolioList[i].excessIncrease) * (1 + accumulatedExcessEarning) - 1;
                XmlElement accumulatedExcessEarningElement = doc.CreateElement("累计超额");
                accumulatedExcessEarningElement.InnerText = accumulatedExcessEarning.ToString();
                portfolioElement.AppendChild(accumulatedExcessEarningElement);

                foreach (Parameter parameter in portfolioList[i].characterList)
                {
                    XmlElement e = doc.CreateElement(parameter.name);
                    e.InnerText = parameter.value.ToString();
                    portfolioElement.AppendChild(e);
                }

                if (isDetailed)
                {

                    XmlElement stocksElement = doc.CreateElement("Stocks");
                    portfolioElement.AppendChild(stocksElement);

                    foreach (TradingStock tradingStock in portfolioList[i].stockList)
                    {
                        XmlElement stockElement = doc.CreateElement("Stock");
                        stocksElement.AppendChild(stockElement);

                        XmlElement e = doc.CreateElement("Code");
                        e.InnerText = tradingStock.code;
                        stockElement.AppendChild(e);

                        e = doc.CreateElement("Name");
                        e.InnerText = tradingStock.name;
                        stockElement.AppendChild(e);

                        e = doc.CreateElement("BuyDate");
                        e.InnerText = tradingStock.buyDate;
                        stockElement.AppendChild(e);

                        e = doc.CreateElement("BuyPrice");
                        e.InnerText = tradingStock.buyPrice.ToString();
                        stockElement.AppendChild(e);

                        e = doc.CreateElement("SellDate");
                        e.InnerText = tradingStock.sellDate;
                        stockElement.AppendChild(e);

                        e = doc.CreateElement("SellPrice");
                        e.InnerText = tradingStock.sellPrice.ToString();
                        stockElement.AppendChild(e);

                        e = doc.CreateElement("Increase");
                        e.InnerText = tradingStock.increase.ToString();
                        stockElement.AppendChild(e);
                    }
                }
            }




        }

        public void saveDoc(string fileName)
        {

            doc.Save(fileName); 
        }
    }
}
